tg-me.com/cpluspluc/1066
Last Update:
🦾 Задача с подвохом: Виртуальные функции и конструкторы
Условие:
Что выведет следующий код и почему?
#include <iostream>
class Base {
public:
Base() {
std::cout << "Base constructor\n";
foo();
}
virtual void foo() {
std::cout << "Base foo\n";
}
};
class Derived : public Base {
public:
Derived() {
std::cout << "Derived constructor\n";
}
void foo() override {
std::cout << "Derived foo\n";
}
};
int main() {
Derived d;
return 0;
}
❓ Вопрос:
Что будет выведено? Почему результат может удивить даже опытных C++ разработчиков?
🔍 Разбор:
1️⃣ Мы создаём объект
Derived d;
Это вызывает конструктор
Derived
2️⃣ В конструкторе
Base
foo();
Может показаться, что поскольку объект на самом деле
Derived
Derived::foo()
Но! Вот главный подвох:
➡️ В C++, когда вы вызываете виртуальную функцию из конструктора (или деструктора), она не виртуальна для объекта, который ещё не полностью сконструирован.
На момент вызова
foo()
Derived
✅ Пошаговое выполнение:
- Вызов конструктора
Base
```
Base constructor
```
- Вызов
foo()
Base
Это вызовет Base::foo(), а не
Derived::foo()
```
Base foo
```
- После завершения конструктора
Base
Derived
```
Derived constructor
```
✅ Итоговый вывод:
```
Base constructor
Base foo
Derived constructor
```
💥 Подвох:
• Многие ожидают, что виртуальные функции работают «магически» всегда.
• Но при вызове из конструктора (или деструктора) виртуальные функции не полиморфны, потому что объект ещё не «стал» Derived полностью.
🛡️ Что нужно помнить:
Никогда не полагайтесь на вызовы виртуальных функций в конструкторах/деструкторах для вызова методов производных классов. Это источник трудноуловимых багов.
✅ Вывод:
C++ строго следует правилам объектной модели: пока объект конструируется (или разрушается), он считается экземпляром того класса, конструктор которого выполняется в данный момент. Это поведение важно помнить при проектировании иерархий классов!
@cpluspluc
BY C++ Academy
Warning: Undefined variable $i in /var/www/tg-me/post.php on line 283
Share with your friend now:
tg-me.com/cpluspluc/1066